package com.slofzx.nuoda.evaluation.project.service.impl;

import com.slofzx.nuoda.common.dto.CompanyDTO;
import com.slofzx.nuoda.common.feign.OfficeClient;
import com.slofzx.nuoda.common.service.impl.BaseServiceImpl;
import com.slofzx.nuoda.common.util.DataConvertUtil;
import com.slofzx.nuoda.common.vo.AjaxResultVO;
import com.slofzx.nuoda.common.vo.CompanyVO;
import com.slofzx.nuoda.evaluation.param.enums.AnalysisTypeEnum;
import com.slofzx.nuoda.evaluation.project.dao.AnalysisDAO;
import com.slofzx.nuoda.evaluation.project.dao.BatchInfoDAO;
import com.slofzx.nuoda.evaluation.project.dto.AnalysisQueryDTO;
import com.slofzx.nuoda.evaluation.project.entity.AnalysisData;
import com.slofzx.nuoda.evaluation.project.entity.BatchInfo;
import com.slofzx.nuoda.evaluation.project.enums.*;
import com.slofzx.nuoda.evaluation.project.service.AnalysisService;
import com.slofzx.nuoda.evaluation.project.util.DoubleUtil;
import com.slofzx.nuoda.evaluation.project.vo.AnalysisDataVO;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class AnalysisServiceImpl extends BaseServiceImpl implements AnalysisService {
    @Autowired
    private AnalysisDAO analysisDAO;

    @Autowired
    private OfficeClient officeClient;
    @Autowired
    private BatchInfoDAO batchInfoDAO;
    /**
     * 按照大区来统计
     * @param dto
     * @return
     */
    @Override
    public List<AnalysisDataVO> queryRegion(AnalysisQueryDTO dto) {
        List<AnalysisDataVO> result = new ArrayList<>();
        if(dto.getBatchId()!=null && !dto.getBatchId().equals("")){
            final List<AnalysisData> analysisDatas = analysisDAO.queryAnalysisVOList(dto);
            if (CollectionUtils.isEmpty(analysisDatas)) {
                return Collections.EMPTY_LIST;
            }
            final Map<String, List<AnalysisData>> listMap = analysisDatas.stream()
                    .filter(f->Objects.nonNull(f) && StringUtils.isNotEmpty(f.getRegion()))
                    .collect(Collectors.groupingBy(AnalysisData::getRegion));
            List<AnalysisDataVO> dataVOList = getAnalysisDataVOS(listMap,AnalysisTypeEnum.REGION);
            final Map<String, AnalysisDataVO> dataVOMap = dataVOList.stream().collect(Collectors.toMap(AnalysisDataVO::getRegion, Function.identity(), (v1, v2) -> v1));
            final BatchInfo batchInfo = batchInfoDAO.selectById(dto.getBatchId());

            if (batchInfo.getProductType().equals(ProductTypeEnum.OIL.getId())){
                for (OilRegionEnum value :  OilRegionEnum.values()) {
                    final AnalysisDataVO analysisDataVO = dataVOMap.get(value.getId());
                    if (Objects.nonNull(analysisDataVO)) {
                        result.add(analysisDataVO);
                    }
                }
            } else {
                for (GasRegionEnum value : GasRegionEnum.values()) {
                    final AnalysisDataVO analysisDataVO = dataVOMap.get(value.getId());
                    if (Objects.nonNull(analysisDataVO)) {
                        result.add(analysisDataVO);
                    }
                }
            }
        }
        return result;
    }

    /**
     * 根据油藏类型统计
     * @param dto
     * @return
     */
    @Override
    public List<AnalysisDataVO> queryPool(AnalysisQueryDTO dto) {
        List<AnalysisDataVO> result = new ArrayList<>();
        if(dto.getBatchId()!=null && !dto.getBatchId().equals("")){
            final List<AnalysisData> analysisDatas = analysisDAO.queryAnalysisVOList(dto);
            if (CollectionUtils.isEmpty(analysisDatas)) {
                return Collections.EMPTY_LIST;
            }
            final Map<String, List<AnalysisData>> listMap = analysisDatas.stream()
                    .filter(f->Objects.nonNull(f) && StringUtils.isNotEmpty(f.getPoolType()))
                    .collect(Collectors.groupingBy(AnalysisData::getPoolType));
            List<AnalysisDataVO> dataVOList = getAnalysisDataVOS(listMap,AnalysisTypeEnum.POOL_TYPE);
            final Map<String, AnalysisDataVO> dataVOMap = dataVOList.stream().collect(Collectors.toMap(AnalysisDataVO::getPoolType, Function.identity(), (v1, v2) -> v1));
            final BatchInfo batchInfo = batchInfoDAO.selectById(dto.getBatchId());

            if (batchInfo.getProductType().equals(ProductTypeEnum.OIL.getId())){
                for (OilPoolTypeEnum value :  OilPoolTypeEnum.values()) {
                    final AnalysisDataVO analysisDataVO = dataVOMap.get(value.getId());
                    if (Objects.nonNull(analysisDataVO)) {
                        result.add(analysisDataVO);
                    }
                }
            } else {
                for (GasPoolTypeEnum value : GasPoolTypeEnum.values()) {
                    final AnalysisDataVO analysisDataVO = dataVOMap.get(value.getId());
                    if (Objects.nonNull(analysisDataVO)) {
                        result.add(analysisDataVO);
                    }
                }
            }
        }
        return result;
    }

    /**
     * 根据建设单位统计
     * @param dto
     * @return
     */
    @Override
    public List<AnalysisDataVO> queryOffice(AnalysisQueryDTO dto) {
        List<AnalysisDataVO> returnVoList = new ArrayList<>();
        if(dto.getBatchId()!=null && !dto.getBatchId().equals("")){
            final List<AnalysisData> analysisDatas = analysisDAO.queryAnalysisVOList(dto);
            if (CollectionUtils.isEmpty(analysisDatas)) {
                return Collections.EMPTY_LIST;
            }
            final Map<String, List<AnalysisData>> listMap = analysisDatas.stream()
                    .filter(f->Objects.nonNull(f) && StringUtils.isNotEmpty(f.getBuildOffice()))
                    .collect(Collectors.groupingBy(AnalysisData::getBuildOffice));
            List<AnalysisDataVO> dataVOList = getAnalysisDataVOS(listMap,AnalysisTypeEnum.OFFICE);
            //排序
            AjaxResultVO<List<CompanyVO>> companyAjax = officeClient.queryListInner(new CompanyDTO());
            List<CompanyVO> companyVOList = companyAjax.getData();
            for (CompanyVO companyVO: companyVOList) {
                for (AnalysisDataVO analysisDataVO: dataVOList) {
                    if(companyVO.getId().equals(analysisDataVO.getBuildOffice())){
                        returnVoList.add(analysisDataVO);
                    }
                }

            }

        }
        return returnVoList;
    }

    /**
     * 根据建新老区统计
     * @param dto
     * @return
     */
    @Override
    public List<AnalysisDataVO> queryArea(AnalysisQueryDTO dto) {
        List<AnalysisDataVO> dataVOList = new ArrayList<>();
        if(dto.getBatchId()!=null && !dto.getBatchId().equals("")){
            final List<AnalysisData> analysisDatas = analysisDAO.queryAnalysisVOList(dto);
            if (CollectionUtils.isEmpty(analysisDatas)) {
                return Collections.EMPTY_LIST;
            }
            final Map<String, List<AnalysisData>> listMap = analysisDatas.stream()
                    .filter(f->Objects.nonNull(f) && StringUtils.isNotEmpty(f.getAreaMark()))
                    .collect(Collectors.groupingBy(AnalysisData::getAreaMark));
            dataVOList =  getAnalysisDataVOS(listMap,AnalysisTypeEnum.AREA_MARK);
        }
        return dataVOList;
    }
    /**
     * 根据产能类型统计
     * @param dto
     * @return
     */
    @Override
    public List<AnalysisDataVO> queryCapacity(AnalysisQueryDTO dto) {
        final List<AnalysisData> analysisDatas = analysisDAO.queryAnalysisVOList(dto);
        if (CollectionUtils.isEmpty(analysisDatas)) {
            return Collections.EMPTY_LIST;
        }
        final Map<String, List<AnalysisData>> listMap = analysisDatas.stream()
                .filter(f->Objects.nonNull(f) && StringUtils.isNotEmpty(f.getCapacityType()))
                .collect(Collectors.groupingBy(AnalysisData::getCapacityType));
        List<AnalysisDataVO> dataVOList = getAnalysisDataVOS(listMap,AnalysisTypeEnum.CAPACITY_TYPE);
        final Map<String, AnalysisDataVO> dataVOMap = dataVOList.stream().collect(Collectors.toMap(AnalysisDataVO::getCapacityType, Function.identity(), (v1, v2) -> v1));
        List<AnalysisDataVO> result = new ArrayList<>();
        final BatchInfo batchInfo = batchInfoDAO.selectById(dto.getBatchId());

        if (batchInfo.getProductType().equals(ProductTypeEnum.OIL.getId())){
            for (OilCapacityTypeEnum value :  OilCapacityTypeEnum.values()) {
                final AnalysisDataVO analysisDataVO = dataVOMap.get(value.getId());
                if (Objects.nonNull(analysisDataVO)) {
                    result.add(analysisDataVO);
                }

            }
        } else {
            for (GasCapacityTypeEnum value : GasCapacityTypeEnum.values()) {
                final AnalysisDataVO analysisDataVO = dataVOMap.get(value.getId());
                if (Objects.nonNull(analysisDataVO)){
                    result.add(analysisDataVO);
                }
            }
        }
        return result;
    }

    /**
     * 组装和计算返回数据
     * @param listMap
     * @param typeEnum
     * @return
     */
    private List<AnalysisDataVO> getAnalysisDataVOS(Map<String, List<AnalysisData>> listMap,AnalysisTypeEnum typeEnum) {
        List<AnalysisDataVO> dataVOList = new ArrayList<>();
        for (String key : listMap.keySet()) {
            final List<AnalysisData> analysisDataList = listMap.get(key);
            if (CollectionUtils.isEmpty(analysisDataList)) {
                continue;
            }
            final AnalysisDataVO vo = new AnalysisDataVO();
//            vo.setProductType(listMap.values().);
            setKey(typeEnum,key,vo);
            // 总投资
            Double totalInvestSum= 0D;
            Double totalInvestPass= 0D;
            Double totalInvestFailed= 0D;
            // 新建产能
            Double newCapacitySum= 0D;
            Double newCapacityPass= 0D;
            Double newCapacityFailed= 0D;
            // 净利润
            Double netProfitSum= 0D;
            Double netProfitPass= 0D;
            Double netProfitFailed= 0D;
            // 基建井数
            Integer infWellCountSum= 0;
            Integer infWellCountPass= 0;
            Integer infWellCountFailed= 0;
            // 基建油井数
            Integer infOilWellCountSum= 0;
            Integer infOilWellCountPass= 0;
            Integer infOilWellCountFailed= 0;
            // 新钻井数
            Integer drillWellCountSum= 0;
            Integer drillWellCountPass= 0;
            Integer drillWellCountFailed= 0;
            Double inputTotalInvestSum= 0D;
            Double inputTotalInvestPass= 0D;
            Double inputTotalInvestFailed= 0D;
            // 年产油合计
            Double sumOilOutputSum= 0D;
            Double sumOilOutputPass= 0D;
            Double sumOilOutputFailed= 0D;


            // 完全成本美元 每桶
            Double totalOperateCostDollarSum =0D;
            Double totalOperateCostDollarPass =0D;
            Double totalOperateCostDollarFailed =0D;
            // 操作成本美元 每桶
            Double operateCostDollarSum =0D;
            Double operateCostDollarPass =0D;
            Double operateCostDollarFailed =0D;
            // 原油商品量美元 每桶
            Double oilCommodityVolumeDollarSum =0D;
            Double oilCommodityVolumeDollarPass =0D;
            Double oilCommodityVolumeDollarFailed =0D;

            for (AnalysisData analysisData : analysisDataList) {
                final Double totalInvest = DataConvertUtil.parse2Double(analysisData.getTotalInvest());
                final Integer infWellCount = DataConvertUtil.parse2Int(analysisData.getInfWellCount());
                final Integer infOilWellCount = DataConvertUtil.parse2Int(analysisData.getInfOilWellCount());
                final Double newCapacity = DataConvertUtil.parse2Double(analysisData.getNewCapacity());
                final Double netProfit = DataConvertUtil.parse2Double(analysisData.getNetProfit());
                final Integer drillWellCount = DataConvertUtil.parse2Int(analysisData.getDrillWellCount());
                Double inputTotalInvest = DataConvertUtil.parse2Double(analysisData.getTotalInvest());
                Double sumOilOutput = DataConvertUtil.parse2Double(analysisData.getSumOilOutput());
//                Double unitOperateCostDollar = DataConvertUtil.parse2Double(analysisData.getUnitOperateCostDollar());
//                Double unitTotalOperateCostDollar = DataConvertUtil.parse2Double(analysisData.getUnitTotalOperateCostDollar());
                Double totalOperateCostDollar = DataConvertUtil.parse2Double(analysisData.getTotalOperateCostDollar());
                Double operateCostDollar = DataConvertUtil.parse2Double(analysisData.getOperateCostDollar());
                Double oilCommodityVolumeDollar = DataConvertUtil.parse2Double(analysisData.getOilCommodityVolumeDollar());
                totalInvestSum += totalInvest;
                newCapacitySum+= newCapacity;
                netProfitSum+= netProfit;
                infWellCountSum+= infWellCount;
                infOilWellCountSum+= infOilWellCount;
                drillWellCountSum+=drillWellCount;
                inputTotalInvestSum+=inputTotalInvest;
                sumOilOutputSum+=sumOilOutput;
//                unitOperateCostDollarSum += unitOperateCostDollar;
//                unitTotalOperateCostDollarSum += unitTotalOperateCostDollar;
                totalOperateCostDollarSum += totalOperateCostDollar;
                operateCostDollarSum += operateCostDollar;
                oilCommodityVolumeDollarSum+= oilCommodityVolumeDollar;
                if (PassTypeEnum.PASS.getId().equals(analysisData.getPassed())) {
                    totalInvestPass += totalInvest;
                    newCapacityPass+= newCapacity;
                    netProfitPass+= netProfit;
                    infWellCountPass+= infWellCount;
                    infOilWellCountPass+= infOilWellCount;
                    drillWellCountPass+=drillWellCount;
                    inputTotalInvestPass+=inputTotalInvest;
                    sumOilOutputPass+=sumOilOutput;
                    operateCostDollarPass += operateCostDollar;
                    totalOperateCostDollarPass += totalOperateCostDollar;
                    oilCommodityVolumeDollarPass += oilCommodityVolumeDollar;
                } else {
                    totalInvestFailed += totalInvest;
                    newCapacityFailed += newCapacity;
                    netProfitFailed+= netProfit;
                    infWellCountFailed+= infWellCount;
                    infOilWellCountFailed+= infOilWellCount;
                    drillWellCountFailed+=drillWellCount;
                    inputTotalInvestFailed+=inputTotalInvest;
                    sumOilOutputFailed+=sumOilOutput;
                    operateCostDollarFailed += operateCostDollar;
                    totalOperateCostDollarFailed += totalOperateCostDollar;
                    oilCommodityVolumeDollarFailed += oilCommodityVolumeDollar;
                }
            }
            // 总投资
            vo.setTotalInvestSum(DoubleUtil.getScale(totalInvestSum/10000,2));
            vo.setTotalInvestPass(DoubleUtil.getScale(totalInvestPass/10000,2));
            vo.setTotalInvestFailed(DoubleUtil.getScale(totalInvestFailed/10000,2));
            vo.setInputTotalInvestSum(DoubleUtil.getScale(inputTotalInvestSum/10000,4));
            vo.setInputTotalInvestPass(DoubleUtil.getScale(inputTotalInvestPass/10000,4));
            vo.setInputTotalInvestFailed(DoubleUtil.getScale(inputTotalInvestFailed/10000,4));
            // 基建井数
            vo.setInfWellCountSum(infWellCountSum);
            vo.setInfWellCountPass(infWellCountPass);
            vo.setInfWellCountFailed(infWellCountFailed);
            // 基建井数
            vo.setInfOilWellCountSum(infOilWellCountSum);
            vo.setInfOilWellCountPass(infOilWellCountPass);
            vo.setInfOilWellCountFailed(infOilWellCountFailed);
            // 新钻井数
            vo.setDrillWellCountSum(drillWellCountSum);
            vo.setDrillWellCountPass(drillWellCountPass);
            vo.setDrillWellCountFailed(drillWellCountFailed);
            // 净利润
            vo.setNetProfitSum(DoubleUtil.getScale(netProfitSum/10000,2));
            vo.setNetProfitPass(DoubleUtil.getScale(netProfitPass/10000,2));
            vo.setNetProfitFailed(DoubleUtil.getScale(netProfitFailed/10000,2));
            // 新建产能
            vo.setNewCapacitySum(DoubleUtil.getScale(newCapacitySum,2));
            vo.setNewCapacityPass(DoubleUtil.getScale(newCapacityPass,2));
            vo.setNewCapacityFailed(DoubleUtil.getScale(newCapacityFailed,2));
            // 单井投资
             Double wellInvestSum = compute(inputTotalInvestSum,drillWellCountSum.doubleValue(),null);
             Double wellInvestPass = compute(inputTotalInvestPass,drillWellCountPass.doubleValue(),null);
             Double wellInvestFailed = compute(inputTotalInvestFailed,drillWellCountFailed.doubleValue(),null);
             vo.setWellInvestSum(DoubleUtil.getScale(wellInvestSum,2));
            vo.setWellInvestPass(DoubleUtil.getScale(wellInvestPass,2));
            vo.setWellInvestFailed(DoubleUtil.getScale(wellInvestFailed,2));
            // 百万吨产能
            Double mTProductivityInvestSum = compute(totalInvestSum,newCapacitySum,100D);
            Double mTProductivityInvestPass = compute(totalInvestPass,newCapacityPass,100D);
            Double mTProductivityInvestFailed = compute(totalInvestFailed,newCapacityFailed,100D);
            vo.setmTProductivityInvestSum(DoubleUtil.getScale(mTProductivityInvestSum,2));
            vo.setmTProductivityInvestPass(DoubleUtil.getScale(mTProductivityInvestPass,2));
            vo.setmTProductivityInvestFailed(DoubleUtil.getScale(mTProductivityInvestFailed,2));
            // 单井EUR
            Double wellEorSum = compute(sumOilOutputSum*10000,infOilWellCountSum.doubleValue(),null);
            Double wellEorPass = compute(sumOilOutputPass*10000,infOilWellCountPass.doubleValue(),null);
            Double wellEorFailed = compute(sumOilOutputFailed*10000,infOilWellCountFailed.doubleValue(),null);
            vo.setWellEorSum(DoubleUtil.getScale(wellEorSum,2));
            vo.setWellEorPass(DoubleUtil.getScale(wellEorPass,2));
            vo.setWellEorFailed(DoubleUtil.getScale(wellEorFailed,2));
            vo.setSumOilOutputSum(DoubleUtil.getScale(sumOilOutputSum,4));
            vo.setSumOilOutputPass(DoubleUtil.getScale(sumOilOutputPass,4));
            vo.setSumOilOutputFailed(DoubleUtil.getScale(sumOilOutputFailed,4));
            // 单位操作成本 美元/桶
            vo.setUnitOperateCostDollarSum(DoubleUtil.getScale(compute(operateCostDollarSum,oilCommodityVolumeDollarSum,null),2));
            vo.setUnitOperateCostDollarPass(DoubleUtil.getScale(compute(operateCostDollarPass,oilCommodityVolumeDollarPass,null),2));
            vo.setUnitOperateCostDollarFailed(DoubleUtil.getScale(compute(operateCostDollarFailed,oilCommodityVolumeDollarFailed,null),2));
            // 单位完全成本 美元/桶
            vo.setUnitTotalOperateCostDollarSum(DoubleUtil.getScale(compute(totalOperateCostDollarSum,oilCommodityVolumeDollarSum,null),2));
            vo.setUnitTotalOperateCostDollarPass(DoubleUtil.getScale(compute(totalOperateCostDollarPass,oilCommodityVolumeDollarPass,null),2));
            vo.setUnitTotalOperateCostDollarFailed(DoubleUtil.getScale(compute(totalOperateCostDollarFailed,oilCommodityVolumeDollarFailed,null),2));
            dataVOList.add(vo);

        }
        return dataVOList;
    }

    private Double compute(Double val1,Double val2,Double val3) {
        Double div=0D;
        if (val2 != null && val2 != 0) {
             div= val1/val2;
            if (val3 != null && val3 != 0){
               div= div/val3;
            }
        }
        return DoubleUtil.getScale(div,2);
    }

    private void setKey(AnalysisTypeEnum analysisTypeEnum, String key, AnalysisDataVO vo) {
        switch (analysisTypeEnum) {
            case OFFICE:
                vo.setBuildOffice(key);
                return;
            case REGION:
                vo.setRegion(key);
                return;
            case AREA_MARK:
                vo.setAreaMark(key);
                return;
            case POOL_TYPE:
                vo.setPoolType(key);
                return;
            case CAPACITY_TYPE:
                vo.setCapacityType(key);
                return;
        }
    }

    /**
     * 查询趋势分析
     * @param dto
     * @return
     */
    @Override
    public List<AnalysisDataVO> queryTend(AnalysisQueryDTO dto) {
        List<AnalysisData> analysisDatas = analysisDAO.queryAnalysisTendVOList(dto);
        if (CollectionUtils.isEmpty(analysisDatas)) {
            return Collections.EMPTY_LIST;
        }
        List<AnalysisDataVO> dataVOList = new ArrayList<>();
        for (AnalysisData analysisData: analysisDatas) {
            AnalysisDataVO vo = new AnalysisDataVO();
            vo.setYear(analysisData.getYear());
            //总投资
            vo.setTotalInvestSum(DoubleUtil.getScale((DataConvertUtil.parse2Double(analysisData.getTotalInvest())/10000D),2));
            //基建井数
            vo.setInfWellCountSum(analysisData.getInfWellCount());
            //新建产能
            vo.setNewCapacitySum(DoubleUtil.getScale(analysisData.getNewCapacity(),2));
            vo.setNetProfitSum(DoubleUtil.getScale(analysisData.getNetProfit()/10000,2));
            //百万吨产能
            vo.setmTProductivityInvestSum(compute(analysisData.getTotalInvest(),analysisData.getNewCapacity(),100D));
            //单井投资
            vo.setWellInvestSum(compute(analysisData.getTotalInvest(), analysisData.getDrillWellCount().doubleValue(),null));
            //单井EOR
            final Double wellEur = compute(analysisData.getSumOilOutput() * 10000, analysisData.getInfOilWellCount().doubleValue(), null);
            vo.setWellEorSum(wellEur);
            vo.setDrillWellCountSum(analysisData.getDrillWellCount());
            vo.setUnitOperateCostDollarSum(compute(analysisData.getOperateCostDollar(),analysisData.getOilCommodityVolumeDollar(),null));
            vo.setUnitTotalOperateCostDollarSum(compute(analysisData.getTotalOperateCostDollar(),analysisData.getOilCommodityVolumeDollar(),null));
            dataVOList.add(vo);
        }
        return dataVOList;
    }
}
